+function($){



/**

 * 定义基础内部全局变量

 */

var 

    /**

     * 当前window对象

     * @type {jQuery Object}

     */

    $win = $(window),



    /**

     * 当前document对象

     * @type {jQuery Object}

     */

    $doc = $(document),



    /**

     * ThinkEditor 对象

     * @type {Object}

     */

    ThinkEditor,



    /**

     * 封装过的textarea Range对象

     * @type {Object}

     */

    Range,



    /**

     * 编辑器弹出层对象

     * 主要提供给一些需要复杂功能的插件使用

     * 在插件中使用 this.dialog()方法调用

     * @type {Object}

     */

    Dialog,



    /**

     * ThinkEditor插件对象，所有的操作都是通过该对象实现

     * @type {Object}

     */

    Plugin = {},



    /**

     * ThinkEditor语言包对象

     */

    Language = {},



    /**

     * 键盘按键对应数值表

     * @type {Object}

     */

    KeyCode = {

        "BACKSPACE" : 8,

        "TAB"       : 9,

        "ENTER"     : 13,

        "ESC"       : 27,

        "SPACE"     : 32,

        "F1"        : 112,

        "F2"        : 113,

        "F3"        : 114,

        "F4"        : 115,

        "F5"        : 116,

        "F6"        : 117,

        "F7"        : 118,

        "F8"        : 119,

        "F9"        : 120,

        "F10"       : 121,

        "F11"       : 122,

        "F12"       : 123

    },



    /**

     * 默认配置项，创建Tree时传入的配置项会和该配置合并

     * @type {Object}

     */

    Defaults = {

        /**

         * 显示风格

         * 目前仅支持默认风格，可自己扩展

         */

        "style" : "default", 

        

        /**

         * 编辑器插件按钮配置

         * 没配置到这里的插件不能显示在工具栏

         * 如果设置了快捷键依然生效

         */

        "items" : "h1,h2,h3,h4,h5,h6,-,link,image,-,bold,italic,code,-," + 

                  "ul,ol,blockquote,hr,-,fullscreen,save",

        

        /**

         * 编辑器默认宽度

         * 默认自适应父容器

         */

        "width" : "100%",

        

        /**

         * 编辑器高度，默认自适应父容器

         * 设置为100%时一定要给父元素设置高度

         */

        "height" : "100%",



        /**

         * 编辑器显示语言

         * 目前仅支持简体中文和英文

         * 可以在调用编辑器之前调用$.thinkeditor.language方法扩展

         */

        "lang" : "zh-cn",

        

        /**

         * 按TAB键插入的字符

         * 默认为四个空格，一般情况下为空格或制表符

         * 插入制表符请写 \t

         */

        "tab" : "    ",



        /**

         * 图片上传插件上传到的URL

         * 该URL必须返回JSON数据

         * 数据格式：

         * {

         *     "status" : 1,

         *     "info"   : "message",

         *     "files"  : [] //文件信息

         * }

         */

        "uploader" : "",



        /**

         * 图片上传表单名称

         * 即<input type="file" name=""/>name属性默认设置的值

         */

        "dataName" : "images",



        /**

         * 保存按钮点击后调用的回调函数

         */

        "onSave" : $.noop //保存按钮回调接口

    },



    DialogWraper = [

        '<div class="thinkeditor-dialog">',

            '<div class="thinkeditor-dialog-header">',

                '<span class="thinkeditor-dialog-title"></span>',

                '<span class="thinkeditor-dialog-close"></span>',

            '</div>',

            '<div class="thinkeditor-dialog-body"></div>',

            '<div class="thinkeditor-dialog-footer">',

                '<div class="thinkeditor-dialog-status"></div>',

                '<div class="thinkeditor-dialog-tools">',

                    '<button type="button" class="thinkeditor-dialog-btn-ok"></button>',

                    '<button type="button" class="thinkeditor-dialog-btn-cancel"></button>',

                '</div>',

            '</div>',

        '</div>'

    ].join("");



/**

 * Range构造器，用于创建一个新的Range对象

 * @param {Object} textarea 一个textarea对象，用于创建Range

 */

Range = function(textarea){

    /* 绑定Range对象的textarea */

    this.textarea = textarea;

}



/**

 * 扩展Range原型，主要添加了get,set,insert三个方法

 * @type {Object}

 */

Range.prototype = {

    /**

     * 获取当前range

     * @return {Object} 当前range对象

     */

    "get" : function(){

        var textarea = this.textarea, 

            data     = {"start" : 0, "end" : 0, "text" : ""},

            range, dupRange, rangeNl, dupRangeNl;



        textarea.focus();

        if (textarea.setSelectionRange) { // W3C  

            data.start = textarea.selectionStart;

            data.end   = textarea.selectionEnd;

            data.text  = (data.start != data.end) ? 

                         textarea.value.substring(data.start, data.end) : "";

        } else if (document.selection) { // For IE

            range    = document.selection.createRange(),

            dupRange = range.duplicate();

            dupRange.moveToElementText(textarea);

            dupRange.setEndPoint("EndToEnd", range );



            data.text  = range.text; //选中的文本内容

            rangeNl    = range.text.split("\n").length - 1; //选中文本换行数

            dupRangeNl = dupRange.text.split("\n").length - 1; //选中之前换行数

            data.start = dupRange.text.length - range.text.length - 

                         dupRangeNl + rangeNl;

            data.end   = data.text.length + data.start - rangeNl;

        }



        return data;

    },



    /**

     * 设置当前range的位置

     * @param  {Integer} start 起始位置

     * @param  {Integer} end   结束位置

     * @return {Object}        当前Range对象

     */

    "set" : function (start, end) {

        var range, textarea = this.textarea;



        textarea.focus();

        if (textarea.setSelectionRange) { // W3C

            textarea.setSelectionRange(start, end);

        } else if (textarea.createTextRange) { // For IE

            range = textarea.createTextRange();

            range.collapse(true);

            range.moveStart("character", start);

            range.moveEnd("character", end - start);

            range.select();

        }



        return this;

    },



    /**

     * 在当前Range处插入文本

     * @param  {String} text 文本内容

     * @return {Object}      当前Range对象

     */

    "insert" : function (text) {

        var textarea = this.textarea, data = this.get(),

            oValue, nValue, range, scroll;

        

        if (textarea.setSelectionRange) { // W3C

            oValue         = textarea.value;

            nValue         = oValue.substring(0, data.start) + text + 

                             oValue.substring(data.end);

            scroll         = textarea.scrollTop;

            data.end       = data.start + text.length;

            textarea.value = nValue;

            

            /**

             * Fixbug:

             * After textarea.values = nValue, scrollTop value to 0

             */

            if(textarea.scrollTop != scroll) {

                textarea.scrollTop = scroll;

            }



            textarea.setSelectionRange(data.start, data.end);

        } else if (textarea.createTextRange) { //For IE

            range      = document.selection.createRange();

            range.text = text;

            range.setEndPoint("StartToEnd", range);

            range.select();

        }



        return this;

    }

};



/**

 * 简单的弹出层对象，供需要弹出显示的插件调用

 * @param {Object} editor  编辑器对象

 * @param {Object} options 编辑器配置对象

 */

Dialog = function(editor, options){

    var self    = this, $dialog, $modal, defaults, 

        $editor = $(editor.range.textarea).closest(".thinkeditor");



    /* 弹出层默认配置 */

    defaults = {

        "title"         : "title",

        "content"       : "<div></div>",

        "onOkClick"     : $.noop,

        "onCancelClick" : $.noop

    }



    //合并配置并创建弹出层

    options = $.extend({}, defaults, options || {});



    /* 创建弹出层内容区 */

    this.dialog = $dialog = $(DialogWraper).appendTo($editor);

    //创建遮罩层

    this.modal  = $modal = $("<div/>").addClass("thinkeditor-dialog-modal")

                           .appendTo($editor);

    

    /* 弹出层相关容器 */

    this.title   = $dialog.find(".thinkeditor-dialog-title"); //标题

    this.content = $dialog.find(".thinkeditor-dialog-body"); //内容

    this.status  = $dialog.find(".thinkeditor-dialog-status"); //状态信息

    

    /* 弹出层按钮 */

    this.btn = {

        "close"  : $dialog.find(".thinkeditor-dialog-close"),

        "ok"     : $dialog.find(".thinkeditor-dialog-btn-ok"),

        "cancel" : $dialog.find(".thinkeditor-dialog-btn-cancel")

    }



    /* 绑定关闭事件 */

    this.btn.close.click(function(){

        self.remove();

    });



    /* 绑定确定按钮事件 */

    this.btn.ok.click(function(){

        options.onOkClick.call(self, this);

    });



    /* 绑定取消按钮事件 */

    this.btn.cancel.click(function(){

        options.onCancelClick.call(self, this);

        self.remove();

    });



    //添加弹出层内容并

    this.setTitle(options.title);

    this.setContent(options.content);

    this.btn.ok.text(editor.lang("ok"));

    this.btn.cancel.text(editor.lang("cancel"));



    //显示弹出层

    $dialog.add($modal).fadeIn("fast");

}



/**

 * 弹出层标准接口

 * @type {Object}

 */

Dialog.prototype = {

    /**

     * 查找弹出层内容里的元素

     * @param  {String} expr jQuery支持的所有选择器

     * @return {Object}      jQuery对象

     */

    "find" : function(expr){

        return this.content.find(expr);

    },



    /**

     * 移动弹出层到屏幕中央

     * @return {Object} 弹出层对象

     */

    "moveToCenter" : function(){

        this.dialog.css({

            "top"  : ($win.height() - this.dialog.outerHeight()) / 2,

            "left" : ($win.width() - this.dialog.outerWidth()) / 2

        });

        return this;

    },



    /**

     * 重置弹出层内容

     * @param  {Object} content 弹出层内容对象，可以是html代码

     * @return {Object}         弹出层对象

     */

    "setContent" : function(content){

        this.content.empty().append(content);

        this.moveToCenter();

        return this;

    },



    /**

     * 改变弹出层标题

     * @param  {String} title 弹出层标题文字，可以是html代码

     * @return {Object}       弹出层对象

     */

    "setTitle" : function(title){

        return this.title.html(title);

    },



    /**

     * 设置弹出层状态信息

     * @param  {String}  info   状态信息

     * @param  {String}  status 状态标识，success，error

     * @param  {Boolean} dealy  是否自动关闭

     * @return {Object}         当前弹出层对象

     */

    "setStatus" : function(info, status, dealy){

        var $status = $("<span/>").text(info), timeout;



        /* 清楚原来计时器 */

        timeout = this.status.children("span").data("timeout");

        timeout && clearTimeout(timeout);



        /* 显示状态信息 */

        status && $status.addClass("thinkeditor-dialog-" + status);

        this.status.empty().append($status);



        /* 延时关闭 */

        if(dealy){

            $status.data("timeout", setTimeout(function(){

                $status.fadeOut("fast");

            }, 5000));

        }

        return this;

    },



    /**

     * 卸载当前弹出层

     */

    "remove" : function(){

        this.dialog.add(this.modal).fadeOut("fast", function(){

            this.remove();

        });

    }

};



/**

 * 创建编辑器工具栏

 * @param  {Object} $editor 编辑器对象

 * @param  {Object} options 配置项

 */

function create_editor_tools($editor, options){

    var self = this, items, groups = options.items.split(",-,"), $group, 

        $tools = $("<div/>");

    

    /* 创建按钮组 */

    for(i in groups){

        items  = groups[i].split(",");

        $group = $("<div/>").addClass("thinkeditor-tools-group")

                 .appendTo($tools);

        for(j in items){

            $("<a/>").addClass("thinkeditor-tools-" + items[j])

                .attr({"title" : this.lang(items[j]), "href" : "javascript:;"})

                .data("name", items[j])

                .appendTo($group);

        }

    }



    /* 工具栏放入editor */

    $tools.addClass("thinkeditor-tools clearfix").prependTo($editor);



    /* 绑定操作事件 */

    $tools.on("click", ".thinkeditor-tools-group a", function(event){

        event.stopPropagation();

        self.plugin($(this).data("name"), options);

    });

}



/**

 * 执行快捷键

 * @param  {event} event 事件对象

 */

function keyboard(event){

    var keyboard = Array(4), 

        self     = event.data.self, 

        options  = event.data.options;



    /* 当前按键 */

    keyboard[0] = event.ctrlKey  ? "ctrl"  : "";

    keyboard[1] = event.shiftKey ? "shift" : "";

    keyboard[2] = event.altKey   ? "alt"   : "";

    keyboard[3] = event.which;

    keyboard    = keyboard.join("");



    /* 执行快捷键 */

    if(self.keyboards[keyboard]){

        if($.isFunction(self.keyboards[keyboard])){

            self.keyboards[keyboard].call(self);

        } else {

            self.plugin(self.keyboards[keyboard], options);

        }

        return false;

    }

}



/**

 * 编辑器构造器，用于创建一个新的编辑器对象

 * @param {Object} textarea 被创建编辑器的textarea对象

 * @param {Object} options  编辑器初始化选项

 */

ThinkEditor = function(textarea, options){

    var options, self = this, $textarea = $(textarea), $editor;



    /* 合并配置项 */

    options = $.extend({}, Defaults, options || {});

    options.width  = options.width  ? options.width  : $textarea.width();

    options.height = options.height ? options.height : $textarea.height();



    /* 创建Range对象 */

    this.range = new Range(textarea);

    this.language = Language[options.lang] ? options.lang : "en-us";



    /* 创建编辑器 */

    $textarea.wrap("<div/>").parent().wrap("<div/>");

    $editor = $textarea.parent().parent();

    $editor.addClass("thinkeditor thinkeditor-" + options.style);

    $editor.children("div").addClass("thinkeditor-textarea");



    /* 设置editor尺寸 */

    $editor.css({"width" : options.width, "height" : options.height});



    /* 创建工具栏 */

    create_editor_tools.call(this, $editor, options);



    /* 绑定快捷键事件 */

    $textarea.keydown({"self" : this, "options" : options}, keyboard);



    /* 绑定插件的快捷键 */

    for(name in Plugin){

        Plugin[name].keyboard && this.keyboard(Plugin[name].keyboard, name);

    }

}



/**

 * 编辑器原型，用于扩展编辑器的外部调用接口

 * @type {Object}

 */

ThinkEditor.prototype = {

    /**

     * 获取语言变量

     * @param  {String} name     变量名

     * @param  {String} language 语言，默认去当前options.lang

     * @return {String}          指定语言的值

     */

    "lang" : function(name, language){

        return Language[language || this.language][name] || name;

    },



    /**

     * 执行某个插件插件

     * @param {String} name    插件名称

     * @param {Object} options 编辑器配置项

     */

    "plugin" : function(name, options){

        var plugin = Plugin[name]

        plugin.markdown.call(this, options, plugin);

        return this;

    },



    /**

     * 插入数据到编辑器光标处

     * @param  {String} text 要插入的数据

     * @return {Object}      ThinkEditor对象

     */

    "insert" : function(text){

        var range = this.range.get(), start, _start, end, length, line = 0;

        if(arguments.length > 1){ //首尾添加文本

            start = arguments[0];

            end   = arguments[1];



            if(arguments[2]){ //按行添加

                text   = range.text.split("\n");

                length = range.text.length;



                /* 逐行添加 */

                for(i in text){

                    if(!length || $.trim(text[i])){

                        _start  = start.replace("{$line}", ++line)

                                       .replace("{$i}", i);

                        text[i] = _start + text[i] + end;

                    }

                }



                /* 插入数据 */

                this.range.insert(text.join("\n"));



                /* 没有选中文本时设置光标位置 */

                if(!length){

                    start = range.start + _start.length;

                    this.range.set(start, start);

                }

            } else {

                this.range.insert(start + range.text + end);

            }

        } else { //插入文本

            this.range.insert(text);

        }

        return this;

    },



    /**

     * 设置或获取编辑器的值

     * @param  {String} text 要设置的值，不传递此参数则获取编辑器的值

     * @return {String}      设置值 - 返回ThinkEditor对象， 获取值 - 返回当前值

     */

    "value" : function(text){

        if(text === undefined){

            return this.range.textarea.value;

        } else {

            this.range.textarea.value = text;

            return this;

        }

    },



    /**

     * 给编辑器绑定快捷键

     * @param  {String}   keys     快捷键名称

     * @param  {Function} callback 触发快捷键时执行额函数或插件名称

     * @return {Object}            当前编辑器对象

     */

    "keyboard" : function(keys, callback){

        var keyboard = Array(4); //[ctrl, shift, alt, code]



        //初始化快捷键

        if(!this.keyboards) { 

            this.keyboards = {};

        }



        keys = keys.toUpperCase().split("+");

        for(i in keys){

            switch(keys[i]){

                case "CTRL" :

                    keyboard[0] = "ctrl";

                    break;

                case "SHIFT" :

                    keyboard[1] = "shift";

                    break;

                case "ALT" :

                    keyboard[2] = "alt";

                    break;

                default:

                    keyboard[3] = KeyCode[keys[i]] || keys[i].charCodeAt();

                    break;

            }

        }

        this.keyboards[keyboard.join("")] = callback;

        return this;

    },



    "dialog" : function(options){

        return new Dialog(this, options);

    }

}



/**

 * 通过textarea获取通过当前textarea创建的ThinkEditor对象

 * @param  {elements} textarea textarea对象或jquery textarea选择器

 * @return {Object}            ThinkEditor对象

 */

$.thinkeditor = function(textarea){

    return $(textarea).data("ThinkEditor");

};



/**

 * 添加ThinkEditor全局扩展

 * 提供对编辑器的语言包，插件，全局设置等功能

 */

$.extend($.thinkeditor, {

    /**

     * 扩展语言包

     * @param  {Object} language 语言包

     */

    "language" : function(language){

        $.extend(Language, $.isPlainObject(language) ? language : {});

    },



    /**

     * 扩展插件

     * @param  {Object} plugin 一个或多个插件

     */

    "plugin" : function(plugin){

        $.extend(Plugin, $.isPlainObject(plugin) ? plugin : {});

    },



    /**

     * 全局设置ThinkEditor

     * @param  {Object} options 要改变的编辑器默认设置项

     */

    "defaults" : function(options){

        $.extend(Defaults, $.isPlainObject(options) ? options : {});

    }

});



/**

 * jQuery.fn对象，用于创建ThinkEditor插件

 * @param  {Object} options ThinkEditor初始化参数

 */

$.fn.thinkeditor = function(options){

    return this.each(function(){

        $(this).data("ThinkEditor", new ThinkEditor(this, options));

    });

}



/**

 * ThinkEditor编辑器插件，工具按显示的每一个按钮代表一个插件

 * 一个合法的插件必须包含markdown方法，用于内部调用

 * 如果需要给插件设置快捷键，则可以通过 keyboard 属性来设置

 * 插件的this指针指向当前ThinkEditor对象

 */

$.thinkeditor.plugin({

    /* 标题一插件 */

    "h1" : {

        /* 标题一快捷键 */

        "keyboard" : "ctrl+1",



        /* 执行标题一 */

        "markdown" : function(options){

            this.insert("# ", "", true);

        }

    },



    /* 标题二插件 */

    "h2" : {

        /* 标题二快捷键 */

        "keyboard" : "ctrl+2",



        /* 执行标题二 */

        "markdown" : function(options){

            this.insert("## ", "", true);

        }

    },



    /* 标题三插件 */

    "h3" : {

        /* 标题三快捷键 */

        "keyboard" : "ctrl+3",



        /* 执行标题三 */

        "markdown" : function(options){

            this.insert("### ", "", true);

        }

    },



    /* 标题四插件 */

    "h4" : {

        /* 标题四快捷键 */

        "keyboard" : "ctrl+4",



        /* 执行标题四 */

        "markdown" : function(options){

            this.insert("#### ", "", true);

        }

    },



    /* 标题五插件 */

    "h5" : {

        /* 标题五快捷键 */

        "keyboard" : "ctrl+5",



        /* 执行标题五 */

        "markdown" : function(options){

            this.insert("##### ", "", true);

        }

    },



    /* 标题六插件 */

    "h6" : {

        /* 标题六快捷键 */

        "keyboard" : "ctrl+6",



        /* 执行标题六 */

        "markdown" : function(options){

            this.insert("###### ", "", true);

        }

    },



    /* 添加链接 */

    "link" : {

        /* 连接快捷键 */

        "keyboard" : "ctrl+l",



        /* 插入连接 */

        "markdown" : function(options){

            var range = this.range.get(), start;



            if(range.text.length){

                if(range.text.match(/^http:\/\/.*/i)){

                    this.insert("[" + range.text + "](" + range.text + ")");

                } else {

                    this.insert("[" + range.text + "]()");

                    start = range.start + range.text.length + 3;

                    this.range.set(start, start);

                }

            } else {

                this.insert("[]()");

                start = range.start + 1;

                this.range.set(start, start);

            }

        }

    },



    /* 添加图片 */

    "image" : {

        /* 图片快捷键 */

        "keyboard" : "ctrl+p",



        /* 插入图片 */

        "markdown" : function(options, self){

            var $text, drop, dialog, start, 

                editor = this, 

                range  = this.range.get();



            /* 当选中文本是远程图片URL时不弹出上传层 */

            if(range.text.length && range.text.match(/^http:\/\/.*/i)){

                this.insert("![ALT](" + range.text + ")");

                start = range.start + 2;

                this.range.set(start, start + 3);

                return;

            }



            //拖动上传容器

            $text     = $("<span/>").text(this.lang("image-text"));

            self.drop = drop = $("<div/>").addClass("thinkeditor-plugin-image")

                               .append($text);

            

            //弹出图片上传层

            self.dialog = dialog = this.dialog({

                "title"     : this.lang("image-title"),

                "content"   : drop,

                "onOkClick" : function(){ self.upload(editor, options) }

            });



            /* 初始化数据对象 */

            self.data = new FormData();

            //初始化文件数

            self.data.length = 0;



            /* 绑定drag事件，主要是用来设置文件放置框的样式 */

            drop.on("dragenter dragleave", function(event){

                drop.toggleClass("thinkeditor-image-draghover");

                event.stopPropagation();

                return false;

            });



            /* 文件拖动事件，不绑定该事件 drop 事件不生效 */            

            drop.on("dragover", function(){ return false });



            /**

             * 文件拖动结束事件

             * 该事件必须用原生方式绑定，拖动结束后浏览器会自动跳转到图片预览页面

             * ？暂不明白是什么原因

             */

            drop[0].addEventListener("drop", function(event) {

                var files = event.target.files || event.dataTransfer.files;



                if(!files) return; //不支持文件拖动

                

                /* 取消拖动样式，阻止事件冒泡及默认事件 */

                drop.removeClass("thinkeditor-image-draghover");

                event.stopPropagation();

                event.preventDefault();



                //上传文件

                self.show(files, options);

            }, false);

        },



        /**

         * 将上传好的图片插入到编辑器

         * @param  {Array}  imgs   上传的图片数组

         * @param  {Object} editor 图片对象

         */

        "insert" : function(imgs, editor){

            var range = editor.range.get(), img, alt, src, text = [];



            for(name in imgs){

                img = imgs[name];

                alt = range.text.length ? range.text : img.name.split(".")[0];

                src = img.rootpath + img.savepath + img.savename;

                text.push("![" + alt + "](" + src + ")");

            }



            editor.insert(text.join("\n"));

            text = text[0];

            editor.range.set(range.start + 2, range.start + text.indexOf("]"));

        },



        /**

         * 预览选择的图片

         * @param  {Object} files   选择的图片对象

         * @param  {Object} options 编辑器配置对象

         */

        "show" : function(files, options){

            var data = this.data, msg;



            for(var i = 0, file; file = files[i]; i++){

                //禁止上传非图片文件

                if(!file.type.match(/^image\/(?:png|jpeg|jpg|gif)$/)){

                    msg = "忽略非图片文件：" + file.name;

                    this.dialog.setStatus(msg, "error", true);

                } else if(file.size > 1024 * 1024 * 10) {

                    msg = "忽略超过大小限制的图片：" + file.name;

                    this.dialog.setStatus(msg, "error", true);

                } else {

                    if(data.length < 3){

                        data.append(options.dataName + i, file);

                        data.length ++;

                        this.reader(file);

                    } else {

                        msg  = "最多同时上传3张图片，";

                        msg += "已忽略" + (files.length - i) + "张";

                        this.dialog.setStatus(msg, "error", true);

                        break;

                    }

                }

            }

        },



        /**

         * 读取图片数据以提供预览

         * @param  {Object} file 图片对象

         */

        "reader" : function(file){

            var self = this, reader = new FileReader(); //初始化文件对象



            /* 展示选择的图片 */

            reader.onload = function(){

                var html = [

                    "<div>", //用于浮动

                        "<span>", //再添加一层标签主要是为了解决图片垂直居中

                            "<img src=\"" + this.result + "\">",

                        "</span>",

                    "</div>"

                ].join("");

                self.drop.append(html);

            }

            reader.readAsDataURL(file);

        },



        /**

         * AJAX上传图片，只有支持HTML的浏览器才能支持该方法

         * @param  {Object} editor  编辑器对象

         * @param  {Object} options 编辑器配置对象

         */

        "upload" : function(editor, options){

            var self = this, xhr = new XMLHttpRequest(), msg;

            if (!xhr.upload) {

                msg = "您的浏览器不支持ajax上传文件！";

                this.dialog.setStatus(msg, "error", true);

                return;

            }



            // 上传中

            xhr.upload.addEventListener("progress", function(event) {

                var progress = Math.round(event.loaded / event.total);

                msg = "正在上传图片..." + progress + "%";

                self.dialog.setStatus(msg, "success");

            }, false);

            

            // 文件上传成功或是失败

            xhr.onreadystatechange = function() {

                var data, images = [];

                if (xhr.readyState == 4) {

                    if (xhr.status == 200) {

                        data = $.parseJSON(xhr.responseText);

                        if(data.status){

                            self.insert(data.files, editor);

                            self.dialog.remove();

                        } else {

                            self.dialog.setStatus(data.info, "error", true);

                        }

                    } else {

                        self.dialog.setStatus("图片上传失败！", "error", true);

                    }

                }

            };



            // 开始上传

            this.dialog.setStatus("正在上传图片...0%", "success");

            xhr.open("POST", options.uploader, true);

            xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");

            xhr.send(this.data); 

        }



    },



    /* 文本加粗插件 */

    "bold" : {

        /* 文本加粗快捷键 */

        "keyboard" : "ctrl+b",



        /* 执行文本加粗 */

        "markdown" : function(options){

            this.insert("**", "**", true);

        }

    },



    /* 文字倾斜插件 */

    "italic" : {

        /* 文字倾斜快捷键 */

        "keyboard" : "ctrl+i",



        /* 执行文字倾斜 */

        "markdown" : function(options){

            this.insert("_", "_", true);

        }

    },



    /* 插入代码 */

    "code" : {

        /* 代码快捷键 */

        "keyboard" : "ctrl+d",



        /* 插入代码 */

        "markdown" : function(options){

            var range = this.range.get(), start;



            if(range.text.length){

                if(range.text.split("\n").length > 1){

                    this.insert("~~~\n"+ range.text +"\n~~~");

                    start = range.start + 3;

                    this.range.set(start, start);

                } else {

                    this.insert("`"+ range.text +"`");

                }

            } else {

                this.insert("``");

                start = range.start + 1;

                this.range.set(start, start);

            }

        }

    },



    /* 无序列表插件 */

    "ul" : {

        /* 代码快捷键 */

        "keyboard" : "ctrl+u",



        /* 插入代码 */

        "markdown" : function(options){

            this.insert("* ", "", true);

        }

    },



    /* 插入有序列表 */

    "ol" : {

        /* 有序列表捷键 */

        "keyboard" : "ctrl+o",



        /* 插入有序列表 */

        "markdown" : function(options){

            this.insert("{$line}. ", "", true);

        }

    },



    /* 引用文本 */

    "blockquote" : {

        /* 引用快捷键 */

        "keyboard" : "ctrl+q",



        /* 插入代码 */

        "markdown" : function(options){

            this.insert("> ", "", true);

        }

    },



    /* 插入水平分割线 */

    "hr" : {

        /* 分割线快捷键 */

        "keyboard" : "ctrl+h",



        /* 插入分割线 */

        "markdown" : function(options){

            var range = this.range.get(), 

                start = range.start + range.text.length + 11;



            this.insert(range.text + "\n* * * * *\n");

            this.range.set(start, start);

        }

    },



    /* 全屏编辑 */

    "fullscreen" : {

        /* 全屏编辑快捷键 */

        "keyboard" : "ctrl+f",



        /* 执行全屏编辑 */

        "markdown" : function(options){

            var $body   = $("body"), 

                $editor = $(this.range.textarea).closest(".thinkeditor");



            if($editor.hasClass("thinkeditor-fullscreen")){

                $body.css("overflow", "");

                $editor.removeClass("thinkeditor-fullscreen");

            } else {

                $body.css("overflow", "hidden");

                $editor.addClass("thinkeditor-fullscreen");

            }

        }

    },



    /* 保存数据 */

    "save" : {

        /* 保存数据快捷键 */

        "keyboard" : "ctrl+s",



        /* 执行全屏编辑 */

        "markdown" : function(options){

            if($.isFunction(options.onSave)){

                options.onSave.call(this.range.textarea);

            }

        }

    },



    /* 文本缩进 */

    "indent" : {

        /* 缩进快捷键 */

        "keyboard" : "tab",



        /* 插入缩进 */

        "markdown" : function(options){

            var range = this.range.get(), text, start;

            if(range.start){

                text  = this.range.textarea.value.substring(0, range.start);

                start = text.lastIndexOf("\n") + 1;

                if(range.text.length && start != text.length){

                    this.range.set(start, range.end);

                }

            }

            this.insert(options.tab, "", true);

        }

    },



    /* 减少缩进 */

    "outdent" : {

        /* 减少缩进快捷键 */

        "keyboard" : "shift+tab",



        /* 插入代码 */

        "markdown" : function(options){

            var range = this.range.get(), text, start;

            if(range.start){

                text  = this.range.textarea.value.substring(0, range.start);

                start = text.lastIndexOf("\n") + 1;

                if(start != text.length){

                    range = this.range.set(start, range.end).get();

                }

            }



            if(range.text.length){

                text = range.text.split("\n");

                for(i in text){

                    text[i] = text[i].replace(/^((\t)|( {1,4}))/, "");

                }

                this.insert(text.join("\n"));

            }

        }

    }

});



/**

 * ThinkEditor编辑器默认语言包

 * 默认仅支持英文和简体中文语言包

 * 其他语言包可以通过 $.thinkeditor.laguage() 方法扩展

 */

$.thinkeditor.language({

    /* 英文语言包 */

    "en-us" : {

        /* 工具栏语言 */

        "h1"         : "H1 (Ctrl+1)",

        "h2"         : "H2 (Ctrl+2)",

        "h3"         : "H3 (Ctrl+3)",

        "h4"         : "H4 (Ctrl+4)",

        "h5"         : "H5 (Ctrl+5)",

        "h6"         : "H6 (Ctrl+6)",

        "link"       : "Link (Ctrl+L)",

        "image"      : "Image (Ctrl+P)",

        "bold"       : "Blod (Ctrl+B)",

        "italic"     : "Italic (Ctrl+I)",

        "code"       : "Code (Ctrl+D)",

        "ul"         : "Unordered List (Ctrl+U)",

        "ol"         : "Ordered List (Ctrl+O)",

        "blockquote" : "Blockquote (Ctrl+Q)",

        "hr"         : "Horizontal Rule (Ctrl+H)",

        "fullscreen" : "Full Screen (Ctrl+F)",

        "save"       : "Save (Ctrl+S)",



        /* 弹出层语言 */

        "ok"     : "OK",

        "cancel" : "Cancel",



        /* 图片插件语言 */

        "image-title" : "Insert Image",

        "image-text"  : "Drag the image to here"

    },



    /* 简体中文语言包 */

    "zh-cn" : {

        /* 工具栏语言 */

        "h1"         : "标题一 (Ctrl+1)",

        "h2"         : "标题二 (Ctrl+2)",

        "h3"         : "标题三 (Ctrl+3)",

        "h4"         : "标题四 (Ctrl+4)",

        "h5"         : "标题五 (Ctrl+5)",

        "h6"         : "标题六 (Ctrl+6)",

        "link"       : "链接 (Ctrl+L)",

        "image"      : "图片 (Ctrl+P)",

        "bold"       : "加粗 (Ctrl+B)",

        "italic"     : "斜体 (Ctrl+I)",

        "code"       : "代码 (Ctrl+D)",

        "ul"         : "无序列表 (Ctrl+U)",

        "ol"         : "有序列表 (Ctrl+O)",

        "blockquote" : "引用 (Ctrl+Q)",

        "hr"         : "分割线 (Ctrl+H)",

        "fullscreen" : "全屏编辑 (Ctrl+F)",

        "save"       : "保存 (Ctrl+S)",



        /* 弹出层语言 */

        "ok"     : "确定",

        "cancel" : "取消",



        /* 图片插件语言 */

        "image-title" : "插入图片",

        "image-text"  : "拖动图片到这里上传"

    }

});



}(jQuery);

